﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SharpMUD.Framework.IO
{
	public class ByteQueueStream : System.IO.Stream
	{
		private object _SyncHandle;
		private Queue<Byte> _InputQueue;
		private Queue<Byte> _OutputQueue;

		private ByteQueueStream() { _SyncHandle = new object(); }
		private ByteQueueStream(Queue<byte> inputQueue, Queue<byte> outputQueue)
		{
			lock (_SyncHandle)
			{
				_InputQueue = inputQueue;
				_OutputQueue = outputQueue;
			}
		}

		public override bool CanRead
		{
			get { return _InputQueue != null; }
		}

		public override bool CanSeek
		{
			get { return false; }
		}

		public override bool CanWrite
		{
			get { return _OutputQueue != null; }
		}

		public override void Flush()
		{
			return;
		}

		public override long Length
		{
			get {
				lock (_SyncHandle)
				{
					long count = 0;

					if (_InputQueue == _OutputQueue && _InputQueue != null)
						return _InputQueue.Count;

					if (_InputQueue == _OutputQueue && _InputQueue == null)
						throw new NotSupportedException();

					if (_InputQueue != null)
						count += _InputQueue.Count;
					if (_OutputQueue != null)
						count += _OutputQueue.Count;

					throw new InvalidOperationException();
				}
			}
		}

		public override long Position
		{
			get
			{
				lock (_SyncHandle)
				{
					if (_InputQueue == _OutputQueue && _InputQueue == null)
						throw new NotSupportedException();

					if (_InputQueue != _OutputQueue && _InputQueue != null && _OutputQueue != null)
						throw new NotSupportedException();

					if (_InputQueue != null)
						return 0;

					if (_OutputQueue != null)
						return _OutputQueue.Count;

					throw new InvalidOperationException();
				}
			}
			set
			{
				throw new NotSupportedException();
			}
		}

		public override long Seek(long offset, System.IO.SeekOrigin origin)
		{
			throw new NotSupportedException();
		}

		public override void SetLength(long value)
		{
			throw new NotSupportedException();
		}

		public override void Write(byte[] buffer, int offset, int count)
		{
			lock (_SyncHandle)
			{
				if (_OutputQueue == null)
					throw new NotSupportedException();

				for (int x = offset; x < (offset + count); x++)
				{
					_OutputQueue.Enqueue(buffer[x]);
				}
			}
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			lock (_SyncHandle)
			{
				if (_InputQueue == null)
					throw new NotSupportedException();

				if (_InputQueue.Count == 0)
				{
					return 0;
				}
				else
				{
					int x;
					for (x = offset;
							x < (offset + count) &&
							x < buffer.Length &&
							_InputQueue.Count > 0;
						x++)
					{
						buffer[x] = _InputQueue.Dequeue();
					}
					return x - offset;
				}
			}
		}

		public static ByteQueueStream ReadWrite(Queue<byte> queue)
		{
			return new ByteQueueStream(queue, queue);
		}

		public static ByteQueueStream ReadWrite(Queue<byte> inputQueue, Queue<byte> outputQueue)
		{
			return new ByteQueueStream(inputQueue, outputQueue);
		}

		public static ByteQueueStream ReadOnly(Queue<byte> inputQueue)
		{
			return new ByteQueueStream(inputQueue, null);
		}

		public static ByteQueueStream WriteOnly(Queue<byte> outputQueue)
		{
			return new ByteQueueStream(null, outputQueue);
		}
	}
}
